home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
comm
/
mail
/
Mutt089src.lha
/
Mutt-0.89i-AMIGA
/
src
/
imap.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-28
|
20KB
|
919 lines
/*
* Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mutt.h"
#include "mutt_curses.h"
#include "mx.h"
#include "mailbox.h"
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
/* Minimal support for IMAP 4rev1 */
#define IMAP_PORT 143
#define SEQLEN 5
/* number of entries in the hash table */
#define IMAP_CACHE_LEN 10
enum
{
IMAP_FATAL = 1,
IMAP_NEW_MAIL,
IMAP_BYE
};
typedef struct
{
int index;
char *path;
} IMAP_CACHE;
typedef struct
{
short status;
unsigned short sequence;
unsigned short newMailCount;
short xxx;
IMAP_CACHE cache[IMAP_CACHE_LEN];
} IMAP_DATA;
static char ImapUser[SHORT_STRING] = { 0 };
static char ImapPass[SHORT_STRING] = { 0 };
static int imap_read_line (char *buf, size_t buflen, int fd)
{
char ch;
int i;
for (i = 0; i < buflen; i++)
{
if (read (fd, &ch, 1) != 1)
return (-1);
if (ch == '\n')
break;
buf[i] = ch;
}
buf[i-1] = 0;
return (i + 1);
}
static int imap_read_line_d (char *buf, size_t buflen, int fd)
{
int r = imap_read_line (buf, buflen, fd);
dprint (1,(debugfile,"imap_read_line_d():%s\n", buf));
return r;
}
static void imap_make_sequence (char *buf, size_t buflen, CONTEXT *ctx)
{
snprintf (buf, buflen, "a%04d", ((IMAP_DATA *) ctx->data)->sequence++);
}
static int imap_write (int fd, const char *buf)
{
dprint (1,(debugfile,"imap_write():%s", buf));
return (write (fd, buf, strlen (buf)));
}
static void imap_error (const char *where, const char *msg)
{
dprint (1, (debugfile, "imap_error(): unexpected response in %s: %s\n", where, msg));
}
/* date is of the form: DD-MMM-YYYY HH:MM:SS +ZZzz */
static time_t imap_parse_date (char *s)
{
struct tm t;
time_t tz;
t.tm_mday = (s[0] - '0') * 10 + (s[1] - '0');
s += 2;
if (*s != '-')
return 0;
s++;
t.tm_mon = mutt_check_month (s);
s += 3;
if (*s != '-')
return 0;
s++;
t.tm_year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0') - 1900;
s += 4;
if (*s != ' ')
return 0;
s++;
/* time */
t.tm_hour = (s[0] - '0') * 10 + (s[1] - '0');
s += 2;
if (*s != ':')
return 0;
s++;
t.tm_min = (s[0] - '0') * 10 + (s[1] - '0');
s += 2;
if (*s != ':')
return 0;
s++;
t.tm_sec = (s[0] - '0') * 10 + (s[1] - '0');
s += 2;
if (*s != ' ')
return 0;
s++;
/* timezone */
tz = ((s[1] - '0') * 10 + (s[2] - '0')) * 3600 +
((s[3] - '0') * 10 + (s[4] - '0')) * 60;
if (s[0] == '+')
tz = -tz;
return (mutt_mktime (&t) + tz);
}
static int imap_parse_fetch (HEADER *h, char *s)
{
char tmp[SHORT_STRING];
char *ptmp;
int state = 0;
if (!s)
return (-1);
h->read = 0;
h->old = 0;
while (*s)
{
SKIPWS (s);
switch (state)
{
case 0:
if (strncasecmp ("FLAGS", s, 5) == 0)
{
s += 5;
SKIPWS (s);
if (*s != '(')
{
dprint (1, (debugfile, "imap_parse_fetch(): bogus FLAGS entry: %s\n", s));
return (-1); /* parse error */
}
s++;
state = 1;
}
else if (strncasecmp ("INTERNALDATE", s, 12) == 0)
{
s += 12;
SKIPWS (s);
if (*s != '\"')
{
dprint (1, (debugfile, "imap_parse_fetch(): bogus INTERNALDATE entry: %s\n", s));
return (-1);
}
s++;
ptmp = tmp;
while (*s && *s != '\"')
*ptmp++ = *s++;
if (*s != '\"')
return (-1);
s++; /* skip past the trailing " */
*ptmp = 0;
h->received = imap_parse_date (tmp);
}
else if (strncasecmp ("RFC822.SIZE", s, 11) == 0)
{
s += 11;
SKIPWS (s);
ptmp = tmp;
while (isdigit (*s))
*ptmp++ = *s++;
*ptmp = 0;
}
else if (*s == ')')
s++; /* end of request */
else
{
/* got something i don't understand */
imap_error ("imap_parse_fetch()", s);
return (-1);
}
break;
case 1: /* flags */
if (*s == ')')
{
s++;
state = 0;
}
else if (strncasecmp ("\\deleted", s, 8) == 0)
{
s += 8;
h->deleted = 1;
}
else if (strncasecmp ("\\flagged", s, 8) == 0)
{
s += 8;
h->flagged = 1;
}
else if (strncasecmp ("\\answered", s, 9) == 0)
{
s += 9;
h->replied = 1;
}
else if (strncasecmp ("\\seen", s, 5) == 0)
{
s += 5;
h->read = 1;
}
else
{
while (*s && !ISSPACE (*s) && *s != ')')
s++;
}
break;
}
}
return 0;
}
static int imap_read_bytes (FILE *fp, int fd, long bytes)
{
long pos;
long len;
char buf[LONG_STRING];
for (pos = 0; pos < bytes; )
{
len = imap_read_line (buf, sizeof (buf), fd);
if (len < 0)
return (-1);
pos += len;
fputs (buf, fp);
fputs ("\n", fp);
}
return 0;
}
/* returns 1 if the command result was OK, or 0 if NO or BAD */
static int imap_code (const char *s)
{
s += SEQLEN;
SKIPWS (s);
return (strncasecmp ("OK", s, 2) == 0);
}
static char *imap_next_word (char *s)
{
while (*s && !ISSPACE (*s))
s++;
SKIPWS (s);
return s;
}
static int imap_handle_untagged (CONTEXT *ctx, char *s)
{
char *pn;
int count;
s = imap_next_word (s);
if (isdigit (*s))
{
pn = s;
s = imap_next_word (s);
if (strncasecmp ("EXISTS", s, 6) == 0)
{
/* new mail arrived */
count = atoi (pn);
if (count <= ctx->msgcount)
{
/* something is wrong because the server reported fewer messages
* than we previously saw
*/
mutt_error ("Fatal error. Message count is out of sync!");
((IMAP_DATA *) ctx->data)->status = IMAP_FATAL;
mx_fastclose_mailbox (ctx);
return (-1);
}
else
{
((IMAP_DATA *) ctx->data)->status = IMAP_NEW_MAIL;
((IMAP_DATA *) ctx->data)->newMailCount = count;
}
}
}
else if (strncasecmp ("BYE", s, 3) == 0)
{
/* server shut down our connection */
s += 3;
SKIPWS (s);
mutt_error (s);
((IMAP_DATA *) ctx->data)->status = IMAP_BYE;
mx_fastclose_mailbox (ctx);
return (-1);
}
else
{
dprint (1, (debugfile, "imap_unhandle_untagged(): unhandled request: %s\n",
s));
}
return 0;
}
static int imap_read_header (CONTEXT *ctx, int msgno)
{
char buf[LONG_STRING];
FILE *fp;
char tempfile[_POSIX_PATH_MAX];
char seq[8];
char *pc;
char *pn;
long bytes;
ctx->hdrs[ctx->msgcount]->index = ctx->msgcount;
mutt_mktemp (tempfile);
if (!(fp = safe_fopen (tempfile, "w+")))
{
return (-1);
}
imap_make_sequence (seq, sizeof (seq), ctx);
snprintf (buf, sizeof (buf), "%s FETCH %d RFC822.HEADER\r\n", seq, msgno + 1);
imap_write (ctx->fd, buf);
do
{
if (imap_read_line (buf, sizeof (buf), ctx->fd) < 0)
{
return (-1);
}
if (buf[0] == '*')
{
pc = buf;
pc = imap_next_word (pc);
pc = imap_next_word (pc);
if (strncasecmp ("FETCH", pc, 5) == 0)
{
if (!(pc = strchr (pc, '{')))
{
imap_error ("imap_read_header()", buf);
return (-1);
}
pc++;
pn = pc;
while (isdigit (*pc))
pc++;
*pc = 0;
bytes = atoi (pn);
imap_read_bytes (fp, ctx->fd, bytes);
}
else if (imap_handle_untagged (ctx, buf) != 0)
return (-1);
}
}
while (strncmp (seq, buf, SEQLEN) != 0);
rewind (fp);
ctx->hdrs[msgno]->env = mutt_read_rfc822_header (fp, ctx->hdrs[msgno]);
fclose (fp);
unlink (tempfile);
/* get the status of this message */
imap_make_sequence (seq, sizeof (seq), ctx);
snprintf (buf, sizeof (buf), "%s FETCH %d FAST\r\n", seq, msgno + 1);
imap_write (ctx->fd, buf);
do
{
if (imap_read_line_d (buf